class X {
  public name: string; // 实例属性

  static x: string = "static x"; // 静态属性, 在react组件中设置state时比较常见

  constructor(name: string) {
    this.name = name;
  }
  static print(): void {
    console.log(this.name, this.x);
    // 静态方法 类似于$.ajax()
    // 无法调用 实例this.name，因为此时this指向这个X构造器，并不是其实例
    // 可以调用 静态属性 this.x，原因同上
  }

  run(): void {
    console.log(this.name);
    // 实例方法 类似于 $().css()
  }
}

const x1 = new X("test");

x1.run(); // 实例方法

X.print(); // 静态方法

// 多态(继承的一种) 嗯，多种状态(子类来体现,有种方法覆盖的感觉)
// 父类定义一个方法不去实现(不知道怎么实现呢)，所以让它的子类去实现， 那么每个子类有不同的表现
class Animal {
  eat(): void {}
}

class Dog extends Animal {
  eat(): void {
    console.log("eat meant");
  }
}

class Cat extends Animal {
  eat(): void {
    console.log("eat mouse");
  }
}

// 抽象类，提供其他类继承的基类，【不能】被实例化。 类似于一个schema(标准), 基于这个schema产生的类中的属性和方法都需要按照这个【结构】来。有点像interface 或者 type
// abstract 在抽象类中定义抽象方法，抽象方法中亦不包含具体实现方法，并且【必须】在派生类中实现/override (类似于vue 中的那个mixin)
// 抽象方法/属性 只能在抽象类中
// 有这样的感觉 - 通过 抽象方法 来 实现了多态 或者说是 占位符
abstract class Animals {
  abstract age: number;

  name: string;

  protected constructor(name: string) {
    this.name = name;
  }

  abstract eat(): void;

  shout(): void {
    console.log(this.name);
  }
}

class Mouse extends Animals {
  age: number;

  constructor(name: string, age: number) {
    super(name);
    this.age = age;
    this.name = name;
  }

  eat(): void {
    console.log("mouse eat");
  }
}

const mouse1 = new Mouse("Mickey", 11);

class Modal {
  // 限制在class及派生类中使用，不能在外面(实例)上使用
  protected visible: boolean;
  constructor() {
    this.visible = false;
  }

  // 通过这种方式来改变protected的值
  toggleVisible() {
    this.visible = !this.visible;
  }
}

class TipModal extends Modal {
  private title: string;

  constructor(title: string) {
    super();
    this.title = title;
  }

  toggleVisible() {
    super.toggleVisible();
  }
}

class WelcomeModal extends Modal {
  constructor(readonly title: string) {
    super();
  }
}

const welcomeModal = new WelcomeModal("test");
console.log(welcomeModal.title);

// 重载
function card(x: number): number;
function card(x: string): string;

function card(x: number | string) {
  return x;
}
